/*-
 * Copyright (C) 2018-2020, Shanghai Trusted Industry Control Platform Co., Ltd.
 * Created by 周正辉 (Zhenghui Zhou) <zhouzhenghui@ticpsh.com>, 赵楷文 (Kaiwen
 * Zhao) <zhaokaiwen@ticpsh.com>
 */

/*-
 * Copyright (C) 2019, Shanghai Trusted Industry Control Platform Co., Ltd.
 * Created by 周正辉 (Zhenghui Zhou) <zhouzhenghui@ticpsh.com>
 */

#ifndef INCREMENTALPARSER_H
#define INCREMENTALPARSER_H

#include <clang/Basic/FileManager.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Parse/Parser.h>

#include <functional>
#include <memory>
#include <string>

namespace rocket {
namespace incparser {

/**
 * @brief 增量解析类
 */
class IncrementalParser {
  friend class IncrementalParserContinuation;

 public:
  /**
   * @brief 构造函数
   * @param CI_: CompilerInstance
   * @note assert(CI_.getPreprocessor().isIncrementalProcessingEnabled() ==
   * true)
   */
  IncrementalParser(clang::CompilerInstance &CI_);
  /**
   * @brief 解析buffer中的代码
   * @param buffer_name: buffer名称字符串
   * @param buffer: 临时的代码缓冲区/字符串
   * @param diag: 用于保存代码解析错误的DiagnosticConsumer
   * @return IncrementalParserContinuation用于捕获解析的声明以及错误
   */
  class IncrementalParserContinuation parse(const std::string &buffer_name,
                                            const std::string &buffer,
                                            clang::DiagnosticConsumer &diag);
  class IncrementalParserContinuation parse(const std::string &code,
                                            clang::DiagnosticConsumer &diag);

 private:
  bool ParseTopLevelDecl(clang::Parser::DeclGroupPtrTy &ADecl) {
#if LLVM_VERSION_MAJOR > 14
    clang::Sema::ModuleImportState mis =
        clang::Sema::ModuleImportState::NotACXX20Module;
    return parser.ParseTopLevelDecl(ADecl, mis);
#else
    return parser.ParseTopLevelDecl(ADecl);
#endif
  }
  clang::CompilerInstance &CI;
  clang::Parser parser;
};

/**
 * @brief 增量解析parser()函数返回的Continuation类
 */
class IncrementalParserContinuation final {
  friend class IncrementalParser;
  IncrementalParserContinuation(
      class IncrementalParser &parser_,
      std::unique_ptr<clang::DiagnosticConsumer> orig_diag_)
      : parser(parser_),
        orig_diag(orig_diag_.release()),
        diag(parser.CI.getDiagnosticClient()),
        NumErrors(diag.getNumErrors()) {}
  IncrementalParserContinuation(const IncrementalParserContinuation &) =
      default;
  IncrementalParserContinuation(IncrementalParserContinuation &&) = default;

 public:
  IncrementalParserContinuation &operator=(
      const IncrementalParserContinuation &) = delete;
  IncrementalParserContinuation &operator=(IncrementalParserContinuation &&) =
      delete;
  /**
   * 解析出TopLevel声明是调用的函数原型
   */
  typedef std::function<bool(clang::DeclGroupRef)> Handle;
  /**
   * 解析诊断错误信息调用的函数原型
   */
  typedef std::function<void()> ErrorHandle;
  /**
   * 设定解析声明时调用的函数
   */
  IncrementalParserContinuation &onTopLevelDecl(Handle &&handle) {
    this->handle = std::move(handle);
    return *this;
  }
  /**
   * 设定诊断错误时调用的函数
   */
  IncrementalParserContinuation &onError(ErrorHandle &&handle) {
    this->error_handle = std::move(handle);
    return *this;
  }
  ~IncrementalParserContinuation();

 private:
  class IncrementalParser &parser;
  clang::DiagnosticConsumer *orig_diag;
  clang::DiagnosticConsumer &diag;
  unsigned NumErrors;
  Handle handle;
  ErrorHandle error_handle;
};

}  // namespace incparser
} /* namespace rocket */

#endif /* INCREMENTALPARSER_H */
